<!doctype html>
<html>
    <head>
        <title>树表组件手册 - HT for Web</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="user-scalable=yes, width=1024">
        <style type="text/css">
            h1, h2, h3, h4, h5, h6, p, blockquote {
                margin: 0;
                padding: 0;
            }
            body {
                font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
                font-size: 13px;
                line-height: 18px;
                color: #737373;
                background-color: white;
                margin: 10px 13px 10px 13px;
            }
            table {
                margin: 10px 0 15px 0;
                border-collapse: collapse;
            }
            td,th {
                border: 1px solid #ddd;
                padding: 3px 10px;
            }
            th {
                padding: 5px 10px;
            }
            a {
                color: #0069d6;
            }
            a:hover {
                color: #0050a3;
                text-decoration: none;
            }
            a img {
                border: none;
            }
            p {
                margin-bottom: 9px;
            }
            h1, h2, h3, h4, h5, h6 {
                color: #404040;
                line-height: 36px;
            }
            h1 {
                margin-bottom: 18px;
                font-size: 30px;
            }
            h2 {
                font-size: 24px;
            }
            h3 {
                font-size: 18px;
            }
            h4 {
                font-size: 16px;
            }
            h5 {
                font-size: 14px;
            }
            h6 {
                font-size: 13px;
            }
            hr {
                margin: 0 0 19px;
                border: 0;
                border-bottom: 1px solid #ccc;
            }
            blockquote {
                padding: 13px 13px 21px 15px;
                margin-bottom: 18px;
                font-family:georgia,serif;
                font-style: italic;
            }
            blockquote:before {
                content:"\201C";
                font-size:40px;
                margin-left:-10px;
                font-family:georgia,serif;
                color:#eee;
            }
            blockquote p {
                font-size: 14px;
                font-weight: 300;
                line-height: 18px;
                margin-bottom: 0;
                font-style: italic;
            }
            code, pre {
                font-family: Monaco, Andale Mono, Courier New, monospace;
            }
            code {
                background-color: #fee9cc;
                color: rgba(0, 0, 0, 0.75);
                padding: 1px 3px;
                font-size: 12px;
                -webkit-border-radius: 3px;
                -moz-border-radius: 3px;
                border-radius: 3px;
            }
            pre {
                display: block;
                padding: 14px;
                margin: 0 0 18px;
                line-height: 16px;
                font-size: 11px;
                border: 1px solid #d9d9d9;
                white-space: pre-wrap;
                word-wrap: break-word;
            }
            pre code {
                background-color: #fff;
                color:#737373;
                font-size: 11px;
                padding: 0;
            }
            sup {
                font-size: 0.83em;
                vertical-align: super;
                line-height: 0;
            }
            * {
                -webkit-print-color-adjust: exact;
            }
            @media screen and (min-width: 914px) {
                body {
                    width: 854px;
                    margin:10px auto;
                }
            }
            @media print {
                body,code,pre code,h1,h2,h3,h4,h5,h6 {
                    color: black;
                }
                table, pre {
                    page-break-inside: avoid;
                }
            }
            iframe{
                width: 100%;
                border: 1px solid #34495E;
                margin: 0;
            }
            .logo{
                vertical-align: middle;
            }

        </style>
        <script>
            function init() {
                var logoSrc = '',
                    logos = document.querySelectorAll('.logo'),
                    i = 0;
                for (; i < logos.length; i++) {
                    logos[i].src = logoSrc;
                }

                var iframes = document.querySelectorAll('iframe'),
                    func = function(){};
                for (i=0; i < iframes.length; i++) {
                    var iframe = iframes[i];

                    // a small hack to make it work on android
                    iframe.ontouchstart = func;

                    if (window.location && window.location.hostname && window.location.hostname.indexOf('hightopo') >= 0) {
                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '<a href="https://hightopo.com/codeeditor/index.html?url=' + iframe.contentWindow.location.pathname + '" target="_blank">在线编辑</a>';
                        iframe.parentNode.insertBefore(div, iframe);

                        var div = document.createElement('div');
                        div.style.float = 'left';
                        div.innerHTML = '&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;';
                        iframe.parentNode.insertBefore(div, iframe);
                    }

                    var div = document.createElement('div');
                    div.innerHTML = '<a href="' + iframe.src + '" target="_blank">独立运行→</a>';
                    iframe.parentNode.insertBefore(div, iframe);
                }
            }
        </script>
    </head>
    <body onload="init();">
        <a href="http://www.hightopo.com"><img class="logo"></a>HT for Web 树表组件手册
        <hr style="margin: 1px 0 20px 0">
<p>索引</p>

<ul><li><a href="#ref_overview">概述</a></li><li><a href="#ref_treetableview">树表组件</a></li></ul>

<hr/>

<div id="ref_overview"></div>

<h2>概述</h2>

<p><code>HT for Web</code>提供了树表组件类<code>ht.widget.TreeTableView</code>，该组件融合了树和表格的展示方式，显示<code>DataModel</code>数据容器中<code>Data</code>对象的父子关系和属性信息，
支持排序和过滤等功能。</p>

<p>通过<code>treeTableView = new ht.widget.TreeTableView(dataModel);</code>初始化构建一个树表组件对象，<code>dataModel</code>参数为树表组件绑定的数据模型，
该模型为空时树表组件构造函数内部将创建一个新的数据模型进行绑定。</p>

<div id="ref_treetableview"></div>

<h2>树表组件</h2>

<p>树表组件类<code>ht.widget.TreeTableView</code>主要可配置属性和函数如下：</p>

<ul><li><code>enableToolTip()</code>和<code>disableToolTip()</code>开启和关闭文字提示</li><li><code>isDisabled()</code>和<code>setDisabled(true/false, iconURL)</code>可获取和设置整个组件处于不可用状态</li><li><code>addTopPainter(func)</code>和<code>removeTopPainter(func)</code>增加和删除顶层绘制器<code>function(g){...}</code></li><li><code>addBottomPainter(func)</code>和<code>removeBottomPainter(func)</code>增加和删除底层绘制器<code>function(g){...}</code></li><li><code>isEditable()</code>和<code>setEditable(true/false)</code>控制可否编辑的总开关，默认为<code>false</code>，每个<code>Column</code>列对象可再控制</li><li><code>isBatchEditable()</code>和<code>setBatchEditable(true/false)</code>控制可否多选时批量编辑总开关，默认为<code>true</code>，每个<code>Column</code>列对象可再控制</li><li><code>getRowHeight()</code>和<code>setRowHeight(20)</code>获取和设置行高</li><li><code>isRowLineVisible()</code>和<code>setRowLineVisible(true/false)</code>获取和设置行线是否可见，默认为<code>true</code></li><li><code>getRowLineColor()</code>和<code>setRowLineColor(color)</code>获取和设置行线颜色</li><li><code>isColumnLineVisible()</code>和<code>setColumnLineVisible()</code>获取和设置列线是否可见，默认为<code>true</code></li><li><code>getColumnLineColor()</code>和<code>setColumnLineColor(color)</code>获取和设置列线颜色</li><li><code>getSortColumn()</code>和<code>setSortColumn(column)</code>获取和设置当前排序列</li><li><code>getSortFunc()</code>和<code>setSortFunc(sortFunc)</code>获取和设置排序函数，在没有<code>sortColumn</code>情况下起作用，决定层次中<code>children</code>显示顺序</li><li><code>isChildrenSortable(parent)</code>判断是否对<code>parent</code>对象的孩子排序，默认返回<code>true</code>，可重载屏蔽孩子排序</li><li><code>isCellEditable(data, column)</code>判断单元格是否可编辑，可重载自定义</li><li><code>getCurrentSortFunc()</code>该函数默认返回<code>sortFunc</code>函数，当<code>sortColumn</code>不为空时将返回其对应的排序函数</li><li><code>getVisibleFunc()</code>和<code>setVisibleFunc()</code>获取和设置可见过滤器，其可过滤<code>DataModel</code>中的<code>Data</code>数据对象</li><li><code>getScrollBarColor()</code>和<code>setScrollBarColor(color)</code>获取和设置滚动条颜色</li><li><code>getScrollBarSize()</code>和<code>setScrollBarSize(6)</code>获取和设置滚动条宽度</li><li><code>isAutoHideScrollBar()</code>和<code>setAutoHideScrollBar(true/false)</code>获取和设置是否自动隐藏滚动条，默认为<code>true</code></li><li><code>getRootData()</code>和<code>setRootData(data)</code>指定树从哪个根节点进行展开，默认从<code>DataModel#getRoots()</code>的对象开始展示</li><li><code>isRootVisible()</code>和<code>setRootVisible(true/false)</code>确定<code>rootData</code>节点是否可见，默认为<code>true</code>，设置为<code>false</code>则隐藏根节点</li><li><code>getCheckMode()</code>和<code>setCheckMode(checkMode)</code>获取和设置当前组件<code>check</code>模式：<ul><li><code>null</code>：默认值，不启用<code>check</code>选择模式</li><li><code>default</code>：<code>check</code>模式的默认选择方式，即单击选中或取消选中，只影响当前点击中的<code>data</code>对象</li><li><code>children</code>：该<code>check</code>模式将同时影响点击中的<code>data</code>对象，以及其孩子对象</li><li><code>descendant</code>：该<code>check</code>模式将同时影响点击中的<code>data</code>对象，以及其所有子孙对象</li><li><code>all</code>：该<code>check</code>模式将同时影响点击中的<code>data</code>对象，以及其所有父辈和子孙对象</li></ul></li><li><code>getCheckIcon(data)</code>返回<code>data</code>对象对应的<code>check</code>图标，可重载自定义<code>check</code>图标，该函数在<code>checkMode</code>模式下有效</li><li><code>getFocusData()</code>、<code>setFocusData(data)</code>和<code>setFocusDataById(id)</code>在<code>checkMode</code>模式下图元除了被选中有<code>check</code>状态外，还可以有被点击行的<code>focus</code>状态</li><li><code>drawRowBackground(g, data, selected, x, y, width, height)</code>绘制行背景色，默认仅在选中该行时填充选中背景色，可重载自定义</li><li><code>drawCell(g, data, selected, column, x, y, width, height)</code>绘制单元格，可重载自定义单元格渲染</li><li><code>drawLabel(g, data, x, y, height)</code>绘制<code>treeColumn</code>文本，可重载自定义，<code>label</code>一般绘制在最后因此没有<code>width</code>参数限制</li><li><code>drawIcon(g, data, x, y, width, height)</code>绘制<code>treeColumn</code>图标，可重载自定义，这里<code>width</code>值取值于<code>getIconWidth</code>函数</li><li><code>getIconWidth(data)</code>返回<code>data</code>对象对应的<code>treeColumn</code>图标宽度，默认如果有图标则以<code>indent</code>值为宽度，可重载自定义</li><li><code>getIndent()</code>和<code>setIndent(20)</code>获取和设置<code>indent</code>缩进，该参数一般用于指定<code>treeColumn</code>图标的宽度</li><li><code>getDataAt(pointOrEvent)</code>传入逻辑坐标点或交互事件<code>event</code>参数，返回对应的<code>data</code>对象或空</li><li><code>getToolTip(event)</code>根据传入的交互事件，返回文本提示信息，可重载自定义</li><li><code>onDataDoubleClicked(data)</code>当<code>data</code>所在行被双击时回调，可重载对双击事件做响应          </li><li><code>onDataClicked(data)</code>当<code>data</code>所在行被单击时回调，可重载对单击事件做响应 </li><li><code>getLabel(data)</code>返回<code>data</code>对象显示的<code>treeColumn</code>文字，默认返回<code>data.toLabel()</code>，可重载自定义</li><li><code>getIcon(data)</code>返回<code>data</code>对象对应<code>treeColumn</code>图标，可重载自定义                    </li><li><code>getLabelFont(data, column, value)</code>返回对应的单元格文本字体，可重载自定义</li><li><code>getLabelColor(data, column, value)</code>返回对应的单元格文本颜色，可重载自定义</li><li><code>getSelectBackground(data)</code>和<code>setSelectBackground(color)</code>获取和设置行选中背景颜色</li><li><code>getStartRowIndex()</code>返回当前可见区域的起始行索引</li><li><code>getEndRowIndex()</code>返回当前可见区域的结束行索引</li><li><code>getRowDatas()</code>返回当前显示的<code>Data</code>对象数组，该数组已被排序和过滤</li><li><code>getRowIndex(data)</code>返回<code>data</code>对象所在的行索引</li><li><code>getRowSize()</code>返回当前可见行总行数</li><li><code>isVisible(data)</code>判断<code>data</code>对象是否可见，可重载自定义</li><li><code>getDataModel()</code>和<code>setDataModel(dataModel)</code>获取和设置绑定的<code>DatModel</code>数据模型</li><li><code>makeVisible(data)</code>该函数触发组件滚动到确保<code>data</code>对象出现在可见区域。</li><li><code>invalidateModel()</code>该函数触发组件重新排序过滤加载数据，一般组件会自动调用，除非数据变化但未派发事件时才需强制调用</li><li><code>redraw()</code>重绘刷新，注意该函数不会触发数据模型的重新加载</li><li><code>invalidateData(data)</code>调用该函数会重绘<code>data</code>对象所在行</li><li><code>getLevel(data)</code>获取当前<code>data</code>的缩减层次，一般结合<code>indent</code>参数用于绘制</li><li><code>getExpandIcon()</code>和<code>setExpandIcon(icon)</code>获取和设置<code>toggle</code>的展开图标</li><li><code>getCollapseIcon()</code>和<code>setCollapseIcon(icon)</code>获取和设置<code>toggle</code>的关闭图标</li><li><code>getToggleIcon(data)</code>返回当前<code>data</code>对象对应的展开或合并图标，可重载自定义</li><li><code>isExpanded(data)</code>判断<code>data</code>对象是否展开</li><li><code>expand(data)</code>展开<code>data</code>对象</li><li><code>onExpanded(data)</code>展开<code>data</code>对象时调用，可重载做后续处理</li><li><code>collapse(data)</code>合并<code>data</code>对象</li><li><code>onCollapsed(data)</code>合并<code>data</code>对象时调用，可重载做后续处理</li><li><code>expandAll()</code>展开所有对象 </li><li><code>collapseAll()</code>合并所有对象</li><li><code>checkData(data)</code>勾选<code>data</code>对象，该函数将根据当前<code>checkMode</code>类型做相应选择处理</li><li><code>getColumnModel()</code>： 表格组件内置一个<code>DataModel</code>类型的列模型，用于存储<code>Column</code>列对象信息</li><li><code>onColumnClicked(column)</code>列头被点击时调用，可重载做后续处理，如远程排序功能 </li><li><code>getTreeColumn()</code>返回树表组件默认插入的树表列，该列显示父子关系的树层次结构</li><li><code>handleDragAndDrop(event, state)</code>该函数默认为空，若该函数被重载，则<code>pan</code>平移组件功能将被关闭<ul><li><code>event</code>鼠标或<code>Touch</code>交互事件</li><li><code>state</code>当前状态，先后会有<code>prepare</code>-<code>begin</code>-<code>between</code>-<code>end</code>四种过程</li></ul></li></ul>

<p><iframe src="examples/example_structure.html" style="height:500px"></iframe></p>

<p><code>TreeTableView</code>默认会自动构建一个<code>treeColumn</code>列，通过<code>treeTableView.getTreeColumn()</code>可得到该列进行属性修改。</p>

<pre><code>treeTableView = treeTablePane.getTableView();  
treeColumn = treeTableView.getTreeColumn();
treeColumn.setDisplayName(&#39;目录结构&#39;);
treeColumn.setAlign(&#39;center&#39;);
treeColumn.setWidth(260);</code></pre>

<p><code>HT</code>的表格和属性页等组件是基于<code>Canvas</code>的<code>2D</code>方式绘制实现界面效果，但为了利用<code>html</code>原生元素的功能，
<code>HT</code>提供了支持<code>html</code>元素和<code>Canvas</code>融合的机制。</p>

<p><code>drawCell</code>除了可以采用常规的<code>2D</code>画笔绘制外，也可以在该函数返回<code>html</code>元素，<code>HT</code>检测到<code>drawCell</code>返回了元素信息后，
将构建一个<code>div</code>作为所返回元素的父容器，用户可以在返回的元素上设置<code>onParentAdded</code>函数，
该函数在元素被添加到父容器后被回调，实现对父容器的自定义。</p>

<p>以下代码在单元格上实现了现实超链接的效果，在<code>onParentAdded</code>函数内设置了<code>div</code>父容器的<code>lineHeight</code>和<code>verticalAlign</code>属性，
实现超链接垂直居中单元格的效果：    </p>

<pre><code>drawCell: function (g, data, selected, column, x, y, w, h) {
    var css_url = data.a(&#39;css_url&#39;);
    if(css_url){
        var css = data.a(&#39;css&#39;),                                    
            href = createHref(css_url, h);                                
        href.setAttribute(&#39;title&#39;, css);
        href.innerHTML = css;
        return href;  
    }
}

function createHref(url, height){
    var href = document.createElement(&#39;a&#39;);
    href.setAttribute(&#39;href&#39;, url);
    href.setAttribute(&#39;target&#39;, &#39;_blank&#39;);
    href.style.whiteSpace = &#39;nowrap&#39;;
    href.style.font = ht.Default.labelFont;
    href.style.paddingLeft = &#39;4px&#39;;
    href.onParentAdded = function(div){
        div.style.lineHeight = height + &#39;px&#39;;                                    
        div.style.verticalAlign = &#39;middle&#39;;
    };
    return href;             
}</code></pre>

<p>与<code>TreeView</code>类似，<code>TreeTableView</code>也具<code>setCheckMode</code>设置为<code>null</code>、<code>&#39;all&#39;</code>、<code>&#39;descendant&#39;</code>、<code>&#39;children&#39;</code>和<code>&#39;default&#39;</code>五种类型：</p>

<pre><code>comboBox: {
    width: 120,
    values: [null, &#39;all&#39;, &#39;descendant&#39;, &#39;children&#39;, &#39;default&#39;],
    onValueChanged: function(){
        treeTableView.sm().cs();
        treeTableView.setCheckMode(this.getValue());
    }                            
}</code></pre>

<p>但处于<code>check</code>模式时，点击行时的选中行效果并非修改<code>SelectionModel</code>，而是修改了<code>TreeTableView</code>的<code>focusData</code>属性，
因此自定义<code>drawRowBackground</code>时，当前背景色需要对<code>check</code>模式下的<code>focusData</code>进行考虑：</p>

<pre><code>treeTableView.drawRowBackground = function(g, data, selected, x, y, width, height){                    
    if((!this.getCheckMode() &amp;&amp; selected) || 
        (this.getCheckMode() &amp;&amp; data === this.getFocusData())) {
        g.fillStyle = &#39;#87A6CB&#39;;
    }
    else if(this.getRowIndex(data) % 2 === 0){
        g.fillStyle = &#39;#F1F4F7&#39;;
    }
    else{
        g.fillStyle = &#39;#FAFAFA&#39;;
    }
    g.beginPath();
    g.rect(x, y, width, height);
    g.fill();
};</code></pre>

<p>该例子仅对<code>core</code>和<code>plugin</code>目录下的孩子节点进行排序，因此重载了<code>isChildrenSortable</code>函数添加了过滤逻辑：</p>

<pre><code>treeTableView.isChildrenSortable = function(data){
    if(data){
        var name = data.getName();
        return name === &#39;core&#39; || name === &#39;plugin&#39;;
    }
    return false;
};</code></pre>

<p>通过工具条的文本输入框实现对<code>TreeTableView</code>的过滤功能，仅过滤孩子节点，不对目录进行过滤，
同时因此输入框文本变化会影响过滤的逻辑，而文本输入过程未有事件派发，因此需要手工监听输入框的<code>onkeyup</code>事件，
在监听到该事件时手工调用<code>treeTableView.invalidateModel()</code>进行表格刷新：</p>

<pre><code>textField = toolbar.getItemById(&#39;text&#39;).element;
textField.getElement().onkeyup = function(e){
    if(e.keyCode === 27){
        textField.getElement().value = &#39;&#39;;
    }
    treeTableView.invalidateModel();
};
treeTableView.setVisibleFunc(function(data){   
    if(data.isEmpty()){
        var text = toolbar.v(&#39;text&#39;);
        if(text){                        
            return data.getName().toLowerCase().indexOf(text.toLowerCase()) &gt;= 0;
        }   
    }
    return true;
});</code></pre>

<p>调用<code>treeTableView.expandAll()</code>张开所有树节点，需注意要在模型数据添加完后进行：</p>

<pre><code>initModel();
treeTableView.expandAll(); </code></pre>

<p> </p>    <hr id="contact" style="margin: 20px 0 1px 0">
    <a href="http://www.hightopo.com"><img class="logo"></a>欢迎交流 <a href="mailto:service@hightopo.com">service@hightopo.com</a>
</body>
</html>
